
#include "SDL.h"
#include "GL/gl3.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"

#include <iostream>
#include <vector>

const GLchar *g_src_fs =
    "float t;"
    "void main(){"
        "t=gl_TexCoord[0].s*.001;"
        "gl_FragColor=vec4(.5+.5*sin(t));"
    "}";

PFNGLCREATESHADERPROGRAMVPROC glCreateShaderProgramv;
PFNGLUSEPROGRAMPROC glUseProgram;

int main() {
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    SDL_WindowID win = SDL_CreateWindow("test3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
    SDL_GL_CreateContext(win);

    glCreateShaderProgramv = reinterpret_cast<PFNGLCREATESHADERPROGRAMVPROC>(SDL_GL_GetProcAddress("glCreateShaderProgramv"));
    glUseProgram = reinterpret_cast<PFNGLUSEPROGRAMPROC>(SDL_GL_GetProcAddress("glUseProgram"));

    glUseProgram(glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &g_src_fs));

    ALCdevice *device = alcOpenDevice(NULL);
    ALCcontext *context = alcCreateContext(device, NULL);
    alcMakeContextCurrent(context);

    std::vector<float> data(44100 * 2);
    for (std::size_t i = 0; i < data.size(); ++i) {
        const float t = i/44100.0f;
        const float w = 2.0f*3.1415926f*220.0f;

        float y = 0.6f*sin(1.0f*w*t)*exp(-0.0008f*w*t);
        y += 0.3f*sin(2.0f*w*t)*exp(-0.0010f*w*t);
        y += 0.1f*sin(4.0f*w*t)*exp(-0.0015f*w*t);
        y += 0.2f*y*y*y;
        y *= 0.9f + 0.1f*cos(70.0f*t);
        y = 2.0f*y*exp(-22.0f*t) + y;

        data[i] = y;
    }

    ALuint buffer;
    alGenBuffers(1, &buffer);
    alBufferData(buffer, AL_FORMAT_MONO_FLOAT32, &data[0], data.size() * sizeof(float), 44100);

    ALuint source;
    alGenSources(1, &source);
    alSourcei(source, AL_BUFFER, buffer);

    alSourcePlay(source);

    bool run = true;
    while (run) {
        SDL_Event evt;
        while (SDL_PollEvent(&evt)) {
            if (evt.type == SDL_KEYDOWN || evt.type == SDL_QUIT) {
                run = false;
            }
        }

        SDL_GL_SwapWindow(win);
    }

    alDeleteSources(1, &source);
    alDeleteBuffers(1, &buffer);

    alcMakeContextCurrent(NULL);
    alcDestroyContext(context);
    alcCloseDevice(device);

    SDL_Quit();

    return 0;
}
